#include <QLibrary>
#include <QFile>

#include "UIApplicationDelegate.h"
#include "UIApplication.h"
#include "UIWindow.h"

typedef int (*UIAppMainFunction) (int argc, char **argv);

// ===========================================================================
//  PRIVATE Class
// ===========================================================================
class UIApplicationPrivate {
    public:
        UIApplicationDelegate *delegate;
        QStringList arguments;
        UIWindow *keyWindow;
};

// ===========================================================================
//  PUBLIC GLOBAL STATIC Instances
// ===========================================================================
Q_GLOBAL_STATIC(UIApplication, uiApplication);

// ===========================================================================
//  PUBLIC STATIC Methods
// ===========================================================================
UIApplication *UIApplication::sharedApplication (void) {
    return(uiApplication());
}

// ===========================================================================
//  PUBLIC STATIC Methods (Env Related)
// ===========================================================================
QString UIApplication::defaultAppDirectory (void) {
    const char *envAppDir = ::getenv("MOKOTOUCH_APPDIR");
    if (envAppDir == NULL) {
#ifdef UIKIT_SIMULATOR
        return("../MOKOTOUCH-DIST/Apps");
#else
        return("/usr/local/MokoTouch/Apps");
#endif
    }
    return(envAppDir);
}

// ===========================================================================
//  PUBLIC Methods
// ===========================================================================
QStringList UIApplication::arguments (void) const {
    return(d->arguments);
}

void UIApplication::setArguments (int argc, char **argv) {
    d->arguments.clear();
    for (int i = 0; i < argc; ++i)
        d->arguments.append(argv[i]);
}

UIWindow *UIApplication::keyWindow (void) const {
    return(d->keyWindow);
}

void UIApplication::setKeyWindow (UIWindow *window) {
    d->keyWindow = window;
    emit keyWindowChanged(d->keyWindow);
}

UIApplicationDelegate *UIApplication::delegate (void) const {
    return(d->delegate);
}

void UIApplication::setDelegate (UIApplicationDelegate *delegate) {
    d->delegate = delegate;
}

QGraphicsView *UIApplication::screenView (void) const {
    if (d->keyWindow == NULL)
        return(NULL);

    QList<QGraphicsView *> views = d->keyWindow->views();
    return(views.size() > 0 ? views.at(0) : NULL);
}

// ===========================================================================
//  PUBLIC Slots
// ===========================================================================
void UIApplication::load (const QString& fileName, const QStringList& args) {
    QLibrary appLib;

    // Open App Library
    appLib.setFileName(fileName);
    if (!appLib.load()) {
        qDebug("UIApplication::load(): %s", qPrintable(appLib.errorString()));
        return;
    }

    // Setup Args
    int argc = args.size() + 1;
    char **argv = new char*[argc];
    argv[0] = fileName.toLatin1().data();
    for (int i = 1; i < argc; ++i)
        argv[i] = args[i - 1].toLatin1().data();

    // Call App main()
    UIAppMainFunction appMain = (UIAppMainFunction)appLib.resolve("main");
    appMain(argc, argv);

    // Destroy Argv
    delete argv;

    // Unload Library
    if (!appLib.unload())
        qDebug("UIApplication::unload(): %s", qPrintable(appLib.errorString()));
}

#include <QDebug>
void UIApplication::loadByName (const QString& appName, const QStringList& args)
{
    QString fileName = QString("%1/%2.app/lib%2.so");
    fileName = fileName.arg(defaultAppDirectory()).arg(appName);

    // If App doesn't exists, Try with the pure load call.
    if (QFile::exists(fileName))
        load(fileName, args);
    else
        load(appName, args);
}

void UIApplication::quit (void) {
    if (d->delegate != NULL)
        d->delegate->applicationWillTerminate(this);

    emit terminated();
}

// ===========================================================================
//  PUBLIC Constructor/Destructor
// ===========================================================================
UIApplication::UIApplication (QObject *parent) 
    : QObject(parent), d(new UIApplicationPrivate)
{
    d->keyWindow = NULL;
    d->delegate = NULL;
}

UIApplication::~UIApplication() {
    delete d;
}

